import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MarkdownTitleMaker {

	enum ReadState {
		PreFindText,
		PreReadText,
		ReadTop,
		ReadTOC,
		ReadText,
	}
	
	private static final Pattern titlePattern = Pattern.compile("^(#+)\\s+([\\d\\.\\\\]+)\\s+(.+)");
	
	private Scanner scanner = null;
	private BufferedWriter writer = null;
	private ReadState readState = ReadState.ReadTop;
	
	private Stack<Integer> titlePrefixIndexes = null;
	private int titleIndex = 0;
	private StringBuffer titleContent = null;
	
	private void makeTitle(String inputPath, String outputPath) {
		
		scanner = null;
		writer = null;
		readState = ReadState.PreFindText;
		titleContent = new StringBuffer();
		
		try {
			scanner = new Scanner(new File(inputPath), "UTF-8");
			writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputPath), "UTF-8"));
			
			while(scanner.hasNextLine()) {
				String line = scanner.nextLine();
				switch(readState) {
				case PreFindText:
					preFindText(line);
					break;
				case PreReadText:
					preReadText(line);
					if(!scanner.hasNextLine()) {
						scanner = new Scanner(new File(inputPath), "UTF-8");
						readState = ReadState.ReadTop;
					}
					break;
				case ReadTop:
					readTop(line);
					break;
				case ReadTOC:
					readTOC(line);
					break;
				case ReadText:
					readText(line);
					break;
				default:
					break;
				}
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if(writer != null) {
				try {
					writer.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	private void preFindText(String line) {
		if(line.startsWith("<!-- /MarkdownTOC -->")) {
			initTile();
			readState = ReadState.PreReadText;
		}
	}
	
	private void preReadText(String line) {
		Matcher match = titlePattern.matcher(line);
		if(!match.find()) {
			return;
		}
		
		String levelTag = match.group(1);
		updateTitle(levelTag.length() - 1);
		String titleNum = titleToString();
		String titleText = match.group(3);
		
		String title = titleNum + " " + titleText;
		String link = "#" + titleNum + "-" + titleText;
		link = link.replaceAll("[\\.\\(\\)\\（\\）/]", "");
		link = link.toLowerCase();
		String content = "";
		for(int i = 0; i < titlePrefixIndexes.size(); i++) {
			content += "  ";
		}
		content += "- [" + title + "](" + link + ")";
		titleContent.append(content);
		titleContent.append("\r\n");
		
	}
	
	private void readTop(String line) throws IOException {
		if(line.startsWith("<!-- MarkdownTOC -->")) {
			readState = ReadState.ReadTOC;
			return;
		}
		
		writer.write(line);
		writer.newLine();
	}
	
	private void readTOC(String line) throws IOException {
		if(line.startsWith("<!-- /MarkdownTOC -->")) {
			writer.write("<!-- MarkdownTOC -->\r\n\r\n");
			writer.write(titleContent.toString());
			writer.write("\r\n<!-- /MarkdownTOC -->\r\n\r\n");
			initTile();
			readState = ReadState.ReadText;
		}
	}
	
	private void readText(String line) throws IOException {
		Matcher match = titlePattern.matcher(line);
		if(!match.find()) {
			writer.write(line);
			writer.newLine();
			return;
		}
		
		String levelTag = match.group(1);
		updateTitle(levelTag.length() - 1);
		String titleNum = titleToString();
		String titleText = match.group(3);
		
		String title = levelTag + " " + titleNum + " " + titleText;
		writer.write(title);
		writer.newLine();
	}
	
	private static String makeNewPath(String path) {
		int index = path.lastIndexOf('.');
		if(index == -1) {
			return path + "_new";
		}
		
		return path.substring(0, index) + "_new" + path.substring(index);
	}
	
	private void initTile() {
		titlePrefixIndexes = new Stack<Integer>();
		titleIndex = 0;
	}
	
	private void increaseTitle() {
		titleIndex++;
	}
	
	private void changeTitleLevel(int newLevel) {
		
		if(newLevel < 1) {
			newLevel = 1;
		}
		
		if(titlePrefixIndexes.size() + 1 < newLevel) { 
			/* enter child title, etc. from 1 to 1.1 */
			/* push the currenet index */
			titlePrefixIndexes.push(titleIndex > 0 ? titleIndex : 1);
			/* etc. from 1 to 1.1.1 */
			while(titlePrefixIndexes.size() + 1 < newLevel) {
				titlePrefixIndexes.push(1);
			}
			titleIndex = 1;
		} else if(titlePrefixIndexes.size() + 1 > newLevel) {
			/* return to parent title, etc. from 1.2 to 1 */
			int lastTitleIndex = 1;
			while(titlePrefixIndexes.size() + 1 > newLevel) {
				lastTitleIndex = titlePrefixIndexes.pop();
			}
			titleIndex = lastTitleIndex + 1;
		} else {
			/* shouldn't call me in this case, however, we have to increase titleIndex */
			increaseTitle();
		}
	}
	
	private void updateTitle(int newLevel) {
		if(titlePrefixIndexes.size() + 1 != newLevel) {
			changeTitleLevel(newLevel);
		} else {
			increaseTitle();
		}
	}
	
	private String titleToString() {
		StringBuffer buffer = new StringBuffer();
		for(Iterator<Integer> iter = titlePrefixIndexes.iterator(); iter.hasNext(); ) {
			int level = iter.next();
			buffer.append(level + ".");
		}
		buffer.append(titleIndex);
		
		return buffer.toString();
	}
	
	public static void usage() {
	    System.out.println("mdtitle input_md");
	}
	
	public static void main(String[] args) {
		
	    if(args.length != 1) {
	        usage();
	        return;
	    }
//		String inputPath = "C:\\Users\\dongb\\Documents\\mplanet\\通信协议.md";
	    String inputPath = args[0];
		String outputPath = makeNewPath(inputPath);
		
		MarkdownTitleMaker maker = new MarkdownTitleMaker();
		maker.makeTitle(inputPath, outputPath);
	}
}
